home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 4
/
Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso
/
Development
/
Source
/
Connection Tool ƒ
/
Definition.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-19
|
26KB
|
874 lines
// ===========================================================================
// "Connection Tool Skeleton in C" for the Communications Toolbox
//
// Copyright © 1994 Peter J. Creath
// All Rights Reserved Worldwide
// ===========================================================================
#include <CRMSerialDevices.h>
#include "ConnToolCommon.h"
// ===========================================================================
// Function prototypes
// ===========================================================================
extern pascal long main(ConnHandle hConn, short msg, long p1, long p2, CMCompletorRecord *pCompletor);
extern CMErr DoInit(ConnHandle hConn);
extern CMErr DoDispose(ConnHandle hConn);
extern CMErr DoSuspend(ConnHandle hConn);
extern CMErr DoResume(ConnHandle hConn);
extern long DoMenu(ConnHandle hConn, short menuID, short menuItem);
extern void DoEvent(ConnHandle hConn, EventRecord *theEvent);
extern CMErr DoActivate(ConnHandle hConn);
extern CMErr DoDeactivate(ConnHandle hConn);
extern CMErr DoIdle(ConnHandle hConn);
extern CMErr DoAbort(ConnHandle hConn);
extern CMErr DoRead(ConnHandle hConn, CMDataBuffer *pData, CMCompletorPtr pCompletor, long timeout);
extern CMErr DoWrite(ConnHandle hConn, CMDataBuffer *pData, CMCompletorPtr pCompletor, long timeout);
extern CMErr DoStatus(ConnHandle hConn, CMBufferSizes *bufferSize, long *theFlag);
extern CMErr DoListen(ConnHandle hConn, CMCompletorPtr pCompletor, long timeout);
extern CMErr DoAccept(ConnHandle hConn, Boolean accept);
extern CMErr DoClose(ConnHandle hConn, CMCompletorPtr pCompletor, long timeout);
extern CMErr DoOpen(ConnHandle hConn, CMCompletorPtr pCompletor, long timeout);
extern CMErr DoBreak(ConnHandle hConn, long duration, CMCompletorPtr pCompletor);
extern CMErr DoIOKill(ConnHandle hConn, short channel);
extern CMErr DoReset(ConnHandle hConn);
extern CMErr DoEnvirons(ConnHandle hConn, ConnEnvironRec *pEnvirons);
// ===========================================================================
// main()
// This function is the entry point for the 'cdef' resource. It passes control to the appropriate
// subroutines, depending on the incoming message. This can probably remain unchanged.
// ===========================================================================
pascal long main(ConnHandle hConn, short msg, long p1, long p2, CMCompletorRecord *pCompletor)
{
long rtnValue;
switch (msg)
{
case cmInitMsg:
rtnValue = DoInit(hConn);
break;
case cmDisposeMsg:
rtnValue = DoDispose(hConn);
break;
case cmSuspendMsg:
rtnValue = DoSuspend(hConn);
break;
case cmResumeMsg:
rtnValue = DoResume(hConn);
break;
case cmMenuMsg:
rtnValue = DoMenu(hConn, p1, p2);
break;
case cmEventMsg:
DoEvent(hConn, (EventRecord *)p1);
break;
case cmActivateMsg:
rtnValue = DoActivate(hConn);
break;
case cmDeactivateMsg:
rtnValue = DoDeactivate(hConn);
break;
case cmIdleMsg:
rtnValue = DoIdle(hConn);
break;
case cmAbortMsg:
rtnValue = DoAbort(hConn);
break;
case cmReadMsg:
rtnValue = DoRead(hConn, (CMDataBufferPtr)p1, pCompletor, p2);
break;
case cmWriteMsg:
rtnValue = DoWrite(hConn, (CMDataBufferPtr)p1, pCompletor, p2);
break;
case cmStatusMsg:
rtnValue = DoStatus(hConn, (CMBufferSizes *)p1, (long *)p2);
break;
case cmListenMsg:
rtnValue = DoListen(hConn, (CMCompletorPtr)p1, p2);
break;
case cmAcceptMsg:
rtnValue = DoAccept(hConn, (Boolean)p1);
break;
case cmCloseMsg:
rtnValue = DoClose(hConn, (CMCompletorPtr)p1, p2);
break;
case cmOpenMsg:
rtnValue = DoOpen(hConn, (CMCompletorPtr)p1, p2);
break;
case cmBreakMsg:
rtnValue = DoBreak(hConn, p1, (CMCompletorPtr)p2);
break;
case cmIOKillMsg:
rtnValue = DoIOKill(hConn, p1);
break;
case cmResetMsg:
rtnValue = DoReset(hConn);
break;
case cmEnvironsMsg:
rtnValue = DoEnvirons(hConn, (ConnEnvironRec *)p1);
break;
default:
rtnValue = cmNotSupported;
break;
}
return (rtnValue);
}
// ===========================================================================
// DoInit()
// This function is called in response to a cmInitMsg. If your tool allocates space for internal
// buffers in the .bufferArray field of the connection record, applications and the Connection
// Manager must NOT manipulate the space. Also, your tools is responsible for freeing the space
// (in DoDispose). You are not required to use the .bufferArray field. This function should return
// an appropriate error, if any.
// ===========================================================================
CMErr DoInit(ConnHandle hConn)
{
CMErr rtnValue;
ConnPtr pConn;
Ptr tempPtr;
PrivatePtr pPrivate;
char handleState;
rtnValue = noErr;
handleState = HGetState((Handle)hConn);
HLock((Handle)hConn);
pConn = *hConn;
pConn->flags |= cmData; // Specify which channels this tool supports
pConn->flags &= (~cmAttn);
pConn->flags &= (~cmCntl);
if (tempPtr = NewPtr(pConn->bufSizes[cmDataIn])) // Allocate memory for the I/O buffers
{
pConn->bufferArray[cmDataIn] = tempPtr;
if (tempPtr = NewPtr(pConn->bufSizes[cmDataOut]))
{
pConn->bufferArray[cmDataOut] = tempPtr;
if (tempPtr = NewPtr(sizeof(PrivateRecord)))
{
pPrivate = (PrivatePtr)tempPtr;
// Fill in private data here
}
else
{
DisposPtr(pConn->bufferArray[cmDataIn]);
DisposPtr(pConn->bufferArray[cmDataOut]);
rtnValue = MemErr;
}
}
else
{
DisposPtr(pConn->bufferArray[cmDataIn]);
rtnValue = MemErr;
}
}
else
{
rtnValue = MemErr;
}
HSetState((Handle)hConn, handleState);
return (rtnValue);
}
// ===========================================================================
// DoDispose()
// This function is called in response to a cmDisposeMsg. It should dispose of any buffers allocated
// in response to cmInitMsg and any private data storage (referenced off of .cmPrivate in the
// connection record). It must NOT attempt to dispose of either .config or .oldConfig in the
// connection record, or of the connection record itself. Doing so WILL cause a system crash!
// ===========================================================================
CMErr DoDispose(ConnHandle hConn)
{
PrivatePtr pPrivate;
CMErr rtnValue;
ConnPtr pConn;
char handleState;
rtnValue = noErr;
handleState = HGetState((Handle)hConn);
HLock((Handle)hConn);
pConn = *hConn;
pPrivate = (PrivatePtr)(pConn->cmPrivate);
if (pPrivate->status & cmStatusOpen) // If the connection is open then call CMClose on it
{
rtnValue = CMClose(hConn, FALSE, (ProcPtr)0L, 0, TRUE);
}
if (rtnValue == noErr) // If the connection is happily closed, release memory
{
DisposPtr((Ptr)(pConn->cmPrivate));
DisposPtr((Ptr)(pConn->bufferArray[cmDataIn]));
DisposPtr((Ptr)(pConn->bufferArray[cmDataOut]));
}
HSetState((Handle)hConn, handleState);
return (rtnValue);
}
// ===========================================================================
// DoSuspend()
// This function is called in response to a cmSuspendMsg. This should do anything needed (like
// remove a menu from the menu bar) in response to a suspend message.
// ===========================================================================
CMErr DoSuspend(ConnHandle hConn)
{
CMErr rtnValue;
PrivatePtr pPrivate;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
return (rtnValue);
}
// ===========================================================================
// DoResume()
// This function is called in response to a cmResumeMsg. This should do anything needed (like add
// a menu to the menu bar) in response to a resume message.
// ===========================================================================
CMErr DoResume(ConnHandle hConn)
{
CMErr rtnValue;
PrivatePtr pPrivate;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
return (rtnValue);
}
// ===========================================================================
// DoMenu()
// This function handles the any menu event passed to it. It should return FALSE if the menu was not
// handled and TRUE if it was.
// ===========================================================================
long DoMenu(ConnHandle hConn, short menuID, short menuItem)
{
long rtnValue;
Boolean isMine;
rtnValue = noErr;
isMine = FALSE; // Perform some check here to see if the menu belongs to this tool
if (isMine)
{
rtnValue = TRUE;
// process the menu command
}
return (rtnValue);
}
// ===========================================================================
// DoEvent()
// This subroutine is called in response to a cmEventMsg. It is called when an event occurs in a
// window associated with the connection tool.
// ===========================================================================
void DoEvent(ConnHandle hConn, EventRecord *theEvent)
{
DialogPtr theDialog;
short theItem;
#define CancelButton 2
if (IsDialogEvent(theEvent))
{
if (DialogSelect(theEvent, &theDialog, &theItem)) // Find out which item was hit
{
switch (theItem)
{
case CancelButton:
// Cancel the connection
break;
}
}
}
else
{
// Handle the keyDown, updateEvt, mouseDown, and any other event here
}
}
// ===========================================================================
// DoActivate()
// This function is called in response to a cmActivateMsg. This should do anything needed (like add
// a menu to the menu bar) in response to an activate message.
// ===========================================================================
CMErr DoActivate(ConnHandle hConn)
{
CMErr rtnValue;
PrivatePtr pPrivate;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
return (rtnValue);
}
// ===========================================================================
// DoDeactivate()
// This function is called in response to a cmDeactivateMsg. This should do anything needed (like
// remove a menu from the menu bar) in response to a deactivate message.
// ===========================================================================
CMErr DoDeactivate(ConnHandle hConn)
{
CMErr rtnValue;
PrivatePtr pPrivate;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
return (rtnValue);
}
// ===========================================================================
// DoIdle()
// This function should check the status of any asynchronous routines and make sure all is well.
// ===========================================================================
CMErr DoIdle(ConnHandle hConn)
{
CMErr rtnValue;
PrivatePtr pPrivate;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
return (rtnValue);
}
// ===========================================================================
// DoAbort()
// This function is called in response to a cmAbortMsg. It should abort the pending listen or open
// process. If no listen or open processes are pending, it should return an error.
// ===========================================================================
CMErr DoAbort(ConnHandle hConn)
{
CMErr rtnValue;
PrivatePtr pPrivate;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
if (pPrivate->status & cmStatusOpening) // If we're trying to open a connection
{
// Stop opening
}
else
{
if (pPrivate->status & cmStatusListenPend) // If we're listening for a connection
{
// Stop listening
}
else
{
return (cmNoRequestPending); // We weren't doing either...
}
}
// Close the physical layer driver
return (rtnValue);
}
// ===========================================================================
// DoRead()
// This function is called in response to a cmReadMsg. It should read data into the buffers specified
// by pData. If a channel is requested that is not supported by this tool, you should return a
// cmNotSupported error. If the tools does not complete the read within the specified time
// (timeout, in ticks), it should pass back a timeout error. If the timeout is -1, then there is no
// timeout. If the timeout is 0, this should read as many bytes, up to toRead bytes, as it can in
// one read attempt.
// ===========================================================================
CMErr DoRead(ConnHandle hConn, CMDataBuffer *pData, CMCompletorPtr pCompletor, long timeout)
{
PrivatePtr pPrivate;
CMErr rtnValue;
ConnPtr pConn;
Boolean doAsync;
short handleState;
rtnValue = noErr;
pData->flags = 0; // Set flags to zero, this tool does not support it
handleState = HGetState((Handle)hConn);
HLock((Handle)hConn);
pConn = *hConn;
pPrivate = (PrivatePtr)(pConn->cmPrivate);
if (pPrivate->status & cmStatusOpen) // Is a connection open?
{
if (pData->channel == cmData)
{
doAsync = FALSE;
if (pCompletor) doAsync = pCompletor->async;
// If async read then install VBL task to check timeout
// Else check the available data to read in the driver buffer
rtnValue = PBRead((ParmBlkPtr)&(pPrivate->myRBlk.theParamBlk), doAsync);
if (rtnValue == noErr)
{
if ((pPrivate->myRBlk.theParamBlk.ioActCount == 0) && doAsync)
{
pData->count = 0;
pConn->asyncCount[cmDataIn] = 0;
}
else
{
pData->count = pPrivate->myRBlk.theParamBlk.ioActCount;
pConn->asyncCount[cmDataIn] = pPrivate->myRBlk.theParamBlk.ioActCount;
}
}
else // There was an error during the read
{
pData->count = 0;
pConn->errCode = rtnValue;
}
}
else // We currently only support the data channel
{
rtnValue = cmNotSupported;
}
}
else // There is no open connection
{
rtnValue = cmNotOpen;
}
HSetState((Handle)hConn, handleState);
return (rtnValue);
}
// ===========================================================================
// DoWrite()
// This function is called in response to a cmWriteMsg. It should write data from the buffers
// specified by pData. If a channel is requested that is not supported by this tool, you should return
// a cmNotSupported error. If the tools does not complete the write within the specified time
// (timeout, in ticks), it should pass back a timeout error. If the timeout is -1, then there is no
// timeout. If the timeout is 0, this should write as many bytes as it can in one write attempt.
// ===========================================================================
CMErr DoWrite(ConnHandle hConn, CMDataBuffer *pData, CMCompletorPtr pCompletor, long timeout)
{
PrivatePtr pPrivate;
CMErr rtnValue;
Boolean doAsync;
ConnPtr pConn;
short handleState;
rtnValue = noErr;
pData->flags = 0; // Set flags to zero, this tool does not support it
handleState = HGetState((Handle)hConn);
HLock((Handle)hConn);
pConn = *hConn;
pPrivate = (PrivatePtr)(pConn->cmPrivate);
if ((pPrivate->status & cmStatusOpen)) // Is a connection open?
{
if (pData->channel == cmData)
{
doAsync = FALSE;
if (pCompletor) doAsync = pCompletor->async;
// If async write then install VBL task to check timeout
// Else check the available data to write to the driver buffer
rtnValue = PBWrite((ParmBlkPtr)&(pPrivate->myWBlk.theParamBlk), doAsync);
if (rtnValue == noErr)
{
if ((pPrivate->myWBlk.theParamBlk.ioActCount == 0) && doAsync)
{
pData->count = 0;
pConn->asyncCount[cmDataIn] = 0;
}
else
{
pData->count = pPrivate->myWBlk.theParamBlk.ioActCount;
pConn->asyncCount[cmDataIn] = pPrivate->myWBlk.theParamBlk.ioActCount;
}
}
else // There was an error during the write
{
pData->count = 0;
pConn->errCode = rtnValue;
}
}
else // We currently only support the data channel
{
rtnValue = cmNotSupported;
}
}
else // There is no open connection
{
rtnValue = cmNotOpen;
}
HSetState((Handle)hConn, handleState);
return (rtnValue);
}
// ===========================================================================
// DoStatus()
// This function is called in response to a cmStatusMsg. It should return the status of the
// connection in hConn. It should also return the sizes of the connection's buffers. Finally, it
// should return the appropriate OSErr or CMErr.
// ===========================================================================
CMErr DoStatus(ConnHandle hConn, CMBufferSizes *bufferSize, long *theFlag)
{
PrivatePtr pPrivate;
CMErr rtnValue;
long count;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
*theFlag = pPrivate->status;
if (pPrivate->status & cmStatusOpen)
{
rtnValue = SerGetBuf(pPrivate->outRefNum, &count); // Check output driver buffer
*bufferSize[cmDataOut] = count;
rtnValue = SerGetBuf(pPrivate->inRefNum, &count); // Check input driver buffer
*bufferSize[cmDataIn] = count;
if (count > 0)
{
*theFlag |= cmStatusDataAvail; // Set the data available bit
*theFlag |= cmStatusOpen; // The connection is established
}
}
else
{
*bufferSize[cmDataIn] = 0;
*theFlag = 0;
}
return (rtnValue);
}
// ===========================================================================
// DoListen()
// This function is called in response to a cmListenMsg. It should wait for an incoming connection
// request. NOTE: pCompletor is created in a local stack frame, so copy any of its contents that
// will be needed later.
// ===========================================================================
CMErr DoListen(ConnHandle hConn, CMCompletorPtr pCompletor, long timeout)
{
PrivatePtr pPrivate;
CMErr rtnValue;
long count;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
if (pPrivate->status & cmStatusOpen)
{
rtnValue = cmNotClosed; // The connection is already open.
}
else
{
// Establish the physical layer driver (open the serial port, etc.)
if (pCompletor->async)
{
// Do async listen call
pPrivate->status |= cmStatusListenPend;
// Issue VBL task to terminate the listen in a specified timeout
}
else
{
// Do sync listen call and return error when timeout
}
}
return (rtnValue);
}
// ===========================================================================
// DoAccept()
// This function is called in response to a cmAcceptMsg. It should accept or reject an incoming
// call based on the value of "accept" passed to it, it should clear the cmStatusIncomingCallPresent
// bit, and it should return the error, if any.
// ===========================================================================
CMErr DoAccept(ConnHandle hConn, Boolean accept)
{
PrivatePtr pPrivate;
CMErr rtnValue;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
if (pPrivate->status & cmStatusOpen) // If the connection is already open, yell at the caller
{
rtnValue = cmNotClosed;
}
else
{
if (accept)
{
pPrivate->status |= cmStatusOpen; // Set the open status bit
}
else
{
// Terminate the logical connection listen process (hang up the modem, etc.)
// Close the physical layer driver (close the serial port, etc.)
}
pPrivate->status &= ~cmStatusIncomingCallPresent;
}
return (rtnValue);
}
// ===========================================================================
// DoClose()
// This function is called in response to a cmCloseMsg. NOTE: pCompletor is created in a local stack
// frame, so copy any of its contents that will be needed later.
// ===========================================================================
CMErr DoClose(ConnHandle hConn, CMCompletorPtr pCompletor, long timeout)
{
PrivatePtr pPrivate;
CMErr rtnValue;
short err;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
if (pPrivate->status & cmStatusOpen)
{
// If break pending, kill break VBL
// If now, kill pending reads and writes
// Else wait for pending reads and writes to clear
if (err = CloseDriver(pPrivate->inRefNum)) rtnValue = err; // Close input and output drivers
if (err = CloseDriver(pPrivate->outRefNum)) rtnValue = err;
// Call completor routine here if async is closed
}
else
{
rtnValue = cmNotOpen;
}
return (rtnValue);
}
// ===========================================================================
// DoOpen()
// This function is called in response to a cmOpenMsg. NOTE: pCompletor is created in a local stack
// frame, so copy any of its contents that will be needed later. This routine is almost entirely
// protocol-specific.
// ===========================================================================
CMErr DoOpen(ConnHandle hConn, CMCompletorPtr pCompletor, long timeout)
{
PrivatePtr pPrivate;
CMErr rtnValue;
ConfigPtr pConfig;
char handleState;
CRMSerialPtr pSerial;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
pConfig = (ConfigPtr)((**hConn).config);
/* pSerial = (CRMSerialPtr)GetSerialPtr(pConfig->portName); // Get the CRM device info
// You get to roll your own GetSerialPtr...use CRMSearch...*/
// Check if drivers are already open.
// If they're already open, warn the application
// First open the output driver, then the input driver
handleState = HGetState((Handle)(pSerial->outputDriverName));
HLock((Handle)(pSerial->outputDriverName));
rtnValue = OpenDriver(*(pSerial->outputDriverName), &(pPrivate->outRefNum));
HSetState((Handle)(pSerial->outputDriverName), handleState);
if (rtnValue == 0) // Output opened successfully
{
handleState = HGetState((Handle)(pSerial->inputDriverName));
HLock((Handle)(pSerial->inputDriverName));
rtnValue = OpenDriver(*(pSerial->inputDriverName), &(pPrivate->inRefNum));
HSetState((Handle)(pSerial->inputDriverName), handleState);
if (rtnValue == 0) // Input opened successfully
{
pPrivate->status = cmStatusOpen;
}
else // Input open failed
{
CloseDriver(pPrivate->outRefNum); // So close the output driver
}
}
// Call completor routine here if async is open
return (rtnValue);
}
// ===========================================================================
// DoBreak()
// This function is called in response to a cmBreakMsg. NOTE: pCompletor is created in a local
// stack frame, so copy any of its contents that will be needed later.
// ===========================================================================
CMErr DoBreak(ConnHandle hConn, long duration, CMCompletorPtr pCompletor)
{
PrivatePtr pPrivate;
CMErr rtnValue;
short err;
long foo;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
if (pPrivate->status & cmStatusOpen)
{
if (pPrivate->breakPending)
{
rtnValue = noErr;
}
else
{
if (pCompletor->async)
{
// Do it asynchronously
// Start the break
// Start a timer (VBL or such) when it finishes it will turn off the break and
// then call the completion routine if necessary.
}
else
{
// Start the break;
Delay(duration, &foo);
// End the break;
}
}
}
else
{
rtnValue = cmNotOpen;
}
return (rtnValue);
}
// ===========================================================================
// DoIOKill()
// This function is called in response to a cmIOKillMsg. It should terminate a pending asynchronous
// input or output request.
// ===========================================================================
CMErr DoIOKill(ConnHandle hConn, short channel)
{
PrivatePtr pPrivate;
CMErr rtnValue;
HIOParam localBlk;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
switch (channel)
{
case cmDataIn:
localBlk.ioRefNum = pPrivate->myRBlk.theParamBlk.ioRefNum;
break;
case cmDataOut:
localBlk.ioRefNum = pPrivate->myWBlk.theParamBlk.ioRefNum;
break;
default:
return (cmNotSupported);
}
localBlk.ioCompletion = 0L;
rtnValue = PBKillIO((ParmBlkPtr)&localBlk, FALSE);
if (rtnValue) (**hConn).errCode = rtnValue;
return (rtnValue);
}
// ===========================================================================
// DoReset()
// This function is called in response to a cmResetMsg. It is entirely protocol-specific.
// ===========================================================================
CMErr DoReset(ConnHandle hConn)
{
PrivatePtr pPrivate;
CMErr rtnValue;
rtnValue = noErr;
pPrivate = (PrivatePtr)((**hConn).cmPrivate);
// Reset your connection (protocol-dependent)
return (rtnValue);
}
// ===========================================================================
// DoEnvirons()
// This function is called in response to a cmEnvironsMsg. It should return information about the
// connection environment.
// ===========================================================================
CMErr DoEnvirons(ConnHandle hConn, ConnEnvironRec *pEnvirons)
{
PrivatePtr pPrivate;
CMErr rtnValue;
ConfigPtr pConfig;
rtnValue = noErr;
pConfig = (ConfigPtr)((**hConn).config);
if (pEnvirons->version < curConnEnvRecVers)
{
rtnValue = envBadVers;
}
else
{
if (pEnvirons->version > 1)
{
rtnValue = envVersTooBig;
}
pEnvirons->dataBits = pConfig->dataBits;
pEnvirons->baudRate = pConfig->baudRate;
pEnvirons->swFlowControl = (pConfig->shaker.fInX && pConfig->shaker.fXOn);
pEnvirons->hwFlowControl = (pConfig->shaker.fDTR && pConfig->shaker.fCTS);
pEnvirons->flags = 0;
pEnvirons->channels = cmData;
}
return (rtnValue);
}